﻿#region 版权声明
/**
 * 版权声明：LumaQQ.NET是基于LumaQQ分析的QQ协议，将其部分代码进行修改和翻译为.NET版本，并且继续使用LumaQQ的开源协议。
 * 本人没有对其核心协议进行改动， 也没有与腾讯公司的QQ软件有直接联系，请尊重LumaQQ作者Luma的著作权和版权声明。
 * 同时在使用此开发包前请自行协调好多方面关系，本人不享受和承担由此产生的任何权利以及任何法律责任。
 * 
 * 作者：阿不
 * 博客：http://hjf1223.cnblogs.com
 * Email：hjf1223 AT gmail.com
 * LumaQQ：http://lumaqq.linuxsir.org 
 * LumaQQ - Java QQ Client
 * 
 * Copyright (C) 2004 luma <stubma@163.com>
 * 
 * LumaQQ - For .NET QQClient
 * Copyright (C) 2008 阿不<hjf1223 AT gmail.com>
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
#endregion
using System;
using System.Collections.Generic;
using System.Text;

using LumaQQ.NET.Net;
using LumaQQ.NET.Events;
using LumaQQ.NET.Packets;
using LumaQQ.NET.Entities;
using LumaQQ.NET.Threading;
using LumaQQ.NET.Packets.In;
using LumaQQ.NET.Packets.Out;
using LumaQQ.NET.Packets.Out._08;
using LumaQQ.NET.Packets.In._08;
namespace LumaQQ.NET
{
    /// <summary>
    /// 登录管理    
    /// </summary>
    public class LoginManager
    {
        private KeepAliveTrigger keepAliveTrigger;
        internal LoginManager() { }
        /// <summary>
        /// 	<remark>abu 2008-03-08 </remark>
        /// </summary>
        /// <value></value>
        public QQClient QQClient { get; private set; }
        public QQUser User { get { return QQClient.QQUser; } }
        internal LoginManager(QQClient client)
        {
            QQClient = client;
        }
        private bool logging = false;
        /**
     * 发送Touch包，使用缺省端口
     *
     * @author luna
     */
        public void SendTouch()
        {
            if (User != null && !logging && QQClient.LoginServer != null)
            {
                // 发送touch
                if (User.IsUdp)
                {
                    SendTouch(QQClient.LoginServer, _08QQ.QQ_PORT_UDP);
                }
                else // TCP方式发送touch
                {
                    SendTouch(QQClient.LoginServer, QQClient.LoginPort);
                }
            }
        }

        /**
     * @author luna
     * <p/>
     * 要先touch才调用login方法
     * <p/>
     * Touch包的发送
     */
        public void SendTouch(String server, int p)
        {
            if (string.IsNullOrEmpty(server) || server.Equals("0.0.0.0"))
            {
                SendTouch();
                // 检查是否设置了用户名和密码
            }
            if (User != null)
            {
                // 停止以前的线程，如果有的话
                Logout();
                // 设置状态为正在登陆
                logging = true;
                // 检查是什么登陆模式，udp还是tcp
                try
                {
                    // 如果port为0，设置缺省port
                    if (p != 0)
                    {
                        if (User.IsUdp)
                        {
                            QQClient.LoginPort = _08QQ.QQ_PORT_UDP;
                        }
                        else
                        {
                            QQClient.LoginPort = p;
                        }
                    }
                    QQClient.LoginServer = server;
                    QQClient.ConnectionManager.ConnectionPool.Release(QQPort.Main.Name);
                    // 构造Touch包
                    _08OutPacket packet = new _08TouchLoginPacket(User);

                    // 发送Touch包
                    QQClient.PacketManager.SendPacketAnyway(packet, QQPort.Main.Name);
                }
                catch (Exception e)
                {
                    QQClient.OnException(e);
                }
            }
        }
        internal void SendToken1()
        {
            _08OutPacket packet = new _08LoginToken1Packet(User);
            QQClient.PacketManager.SendPacketAnyway(packet, QQPort.Main.Name);
        }
        /// <summary>
        ///  发送LoginToken2
        /// </summary>
        /// <param name="token">The token.</param>
        /// <param name="verifyCode">The verify code.</param>
        /// <param name="fragmentIndex">Index of the fragment.</param>
        public void SendToken2(byte[] token, String verifyCode, int fragmentIndex)
        {
            _08LoginToken2Packet packet = new _08LoginToken2Packet(User);
            if (fragmentIndex != 0)
            {
                packet.SubCommand = _08QQ.SubCMD_GetLoginToken.QQ_SUB_COMMAND_GET_LOGIN_TOKEN_EX;
            }
            else
            {
                packet.SubCommand = _08QQ.SubCMD_GetLoginToken.QQ_SUB_CMD_SUBMIT_VERTIFY_CODE_EX;
            }
            packet.VerifyCode = verifyCode;
            packet.FragmentIndex = (byte)fragmentIndex;
            packet.PuzzleToken = token;
            QQClient.PacketManager.SendPacketAnyway(packet, QQPort.Main.Name);
        }
        private void SendToken2()
        {
            _08OutPacket packet = new _08LoginToken2Packet(User);
            QQClient.PacketManager.SendPacketAnyway(packet, QQPort.Main.Name);
        }

        //public void SubmitVerifyCode(byte[] token, String verifyCode)
        //{
        //    GetLoginTokenPacket packet = new GetLoginTokenPacket(User);
        //    packet.SubCommand = _08QQ.SubCMD_GetLoginToken.QQ_SUB_CMD_SUBMIT_VERIFY_CODE;
        //    packet.PuzzleToken = token;
        //    packet.VerifyCode = verifyCode;
        //    QQClient.PacketManager.SendPacketAnyway(packet, QQPort.Main.Name);
        //}

        /// <summary>
        /// 发送登录请求包
        /// </summary>
        /// 发送登录请求包
        /// @author seraph 
        public void SendLoginKey()
        {
            _08OutPacket packet = new _08LoginKeyPacket(User);
            QQClient.PacketManager.SendPacketAnyway(packet, QQPort.Main.Name);
        }

        private void SendLogin()
        {
            _08OutPacket packet = new _08LoginPacket(User);
            QQClient.PacketManager.SendPacketAnyway(packet, QQPort.Main.Name);
        }

        /// <summary>
        /// 发送keep alive包
        /// </summary>
        /// 发送keep alive包     
        public void KeepAlive()
        {
            if (User.IsLoggedIn)
            {
                _08KeepAlivePacket packet = new _08KeepAlivePacket(User);
                SendPacket(packet);
            }
        }

        private void SendPacket(_08BasicOutPacket outpacket)
        {
            QQClient.PacketManager.SendPacket(outpacket, QQPort.Main.Name);
        }

        public void User_AuthInfoOpPacket(int friendQQ)
        {
            _08AuthInfoOpPacket packet = new _08AuthInfoOpPacket(User);
            packet.SubCommand = _08QQ.SubCMD_Auth_Info.QQ_SUB_CMD_GET_AUTH_INFO;
            if (friendQQ != 0)
            {
                packet.SubSubCommand = _08QQ.SubSubCMD_Auth_Info.QQ_SUB_SUB_CMD_GET_FRIEND_AUTH_INFO;
                packet.FriendQQ = friendQQ;
            }
            else
            {
                packet.SubSubCommand = _08QQ.SubSubCMD_Auth_Info.QQ_SUB_SUB_CMD_GET_SIGNATURE_AUTH_INFO;
            }
            QQClient.PacketManager.SendPacket(packet, QQPort.Main.Name);
        }
        /// <summary>
        /// 退出QQ会话
        /// </summary>           
        public void Logout()
        {
            LogoutPacket packet = new LogoutPacket(User);
            SendPacket(packet);

            // 得到当前登录状态
            bool isLoggedIn = User.IsLoggedIn;
            // 设置用户状态
            if (!QQClient.LoginRedirect)
            {
                User.LoginToken = null;
            }
            User.IsLoggedIn = false;
            // 设置正在登录标志为false
            logging = false;
            QQClient.LoginRedirect = false;


            //// 清空发送队列
            //if (pool != null)
            //{
            //    IConnection con = pool.getConnection(MAIN.name);
            //    if (con != null)
            //    {
            //        con.clearSendQueue();
            //        // 如果已经登录了，则发送logout包
            //        if (isLoggedIn)
            //        {

            //        }
            //    }
            //    pool.dispose();
            //}
            //pool = poolFactory.newPool();

            //// 执行清理工作
            //if (keepAliveFuture != null)
            //{
            //    keepAliveFuture.cancel(false);
            //    keepAliveFuture = null;
            //}
            //resendTrigger.clear();
        }
        private void ProcessLoginSuccess()
        {
            if (!User.IsLoggedIn)
            {
                User.IsLoggedIn = true;
                this.logging = false;
                // 请求密钥
                Common_RequestKey(_08QQ.SubCMD_Request_Key.QQ_SUB_CMD_REQUEST_UNKNOWN03_KEY);
                Common_RequestKey(_08QQ.SubCMD_Request_Key.QQ_SUB_CMD_REQUEST_FILE_AGENT_KEY);
                Common_RequestKey(_08QQ.SubCMD_Request_Key.QQ_SUB_CMD_REQUEST_UNKNOWN06_KEY);
                Common_RequestKey(_08QQ.SubCMD_Request_Key.QQ_SUB_CMD_REQUEST_UNKNOWN07_KEY);
                Common_RequestKey(_08QQ.SubCMD_Request_Key.QQ_SUB_CMD_REQUEST_UNKNOWN08_KEY);
                //// 得到我的信息
                //GetUserInfoPacket guiPacket = new GetUserInfoPacket(User);
                //SendPacket(guiPacket);
                //// 手动更改我的在线状态，虽然服务器可能也会给我发送这样的信息
                //ChangeStatusPacket csPacket = new ChangeStatusPacket(User);
                //csPacket.ShowFakeCam = User.IsShowFakeCam;
                //SendPacket(csPacket);
                // 调度keep alive动作
                keepAliveTrigger = new KeepAliveTrigger(this.QQClient);
                //keepAliveFuture = (ScheduledFuture<Object>)executor.scheduleWithFixedDelay(keepAliveTrigger,
                //        _08QQ.QQ_INTERVAL_KEEP_ALIVE,
                //        _08QQ.QQ_INTERVAL_KEEP_ALIVE, TimeUnit.MILLISECONDS);
            }
        }
        /// <summary>
        /// 请求密钥
        /// </summary>
        /// <param name="request">The request.</param>
        /// 请求密钥
        /// @param request 没研究过，不懂
        public void Common_RequestKey(_08QQ.SubCMD_Request_Key request)
        {
            if (User.IsLoggedIn)
            {
                GetKeyPacket packet = new GetKeyPacket(User);
                packet.Request = request;
                QQClient.PacketManager.SendPacket(packet, QQPort.Main.Name);
            }
        }
        #region events
        public event EventHandler<QQEventArgs<_08FirstLoginPacket, _08FirstLoginReplyPacket>> FirstLogin;
        internal void OnFirstLogin(QQEventArgs<_08FirstLoginPacket, _08FirstLoginReplyPacket> e)
        {
            //
            SendLogin();
            if (FirstLogin != null)
            {
                FirstLogin(this.QQClient, e);
            }
        }

        public event EventHandler<QQEventArgs<_08TouchLoginPacket, _08TouchLoginReplyPacket>> SentTouchSuccessfully;
        internal void OnSentTouchSuccessfully(QQEventArgs<_08TouchLoginPacket, _08TouchLoginReplyPacket> e)
        {
            //
            SendToken1();
            if (SentTouchSuccessfully != null)
            {
                SentTouchSuccessfully(this.QQClient, e);
            }
        }
        public event EventHandler<QQEventArgs<_08LoginToken1Packet, _08LoginToken1ReplyPacket>> GetLoginToken1Successfully;
        internal void OnGetLoginToken1Successfully(QQEventArgs<_08LoginToken1Packet, _08LoginToken1ReplyPacket> e)
        {
            //
            SendToken2();
            if (GetLoginToken1Successfully != null)
            {
                GetLoginToken1Successfully(this.QQClient, e);
            }
        }

        public event EventHandler<QQEventArgs<_08LoginToken2Packet, _08LoginToken2ReplyPacket>> GetLoginToken2Successfully;
        internal void OnGetLoginToken2Successfully(QQEventArgs<_08LoginToken2Packet, _08LoginToken2ReplyPacket> e)
        {
            //
            SendLoginKey();
            if (GetLoginToken2Successfully != null)
            {
                GetLoginToken2Successfully(this.QQClient, e);
            }
        }

        /// <summary>
        /// 登录需要验证码
        /// </summary>
        public event EventHandler<QQEventArgs<_08LoginToken2Packet, _08LoginToken2ReplyPacket>> NeedVerifyCode;
        /// <summary>
        /// Raises the <see cref="E:NeedVerifyCode"/> event.
        /// </summary>
        /// <param name="e">The <see cref="LumaQQ.NET.Events.QQEventArgs&lt;LumaQQ.NET.Packets.Out._08._08LoginToken2Packet,LumaQQ.NET.Packets.In._08._08LoginToken2ReplyPacket&gt;"/> instance containing the event data.</param>
        internal void OnNeedVerifyCode(QQEventArgs<_08LoginToken2Packet, _08LoginToken2ReplyPacket> e)
        {
            User.PuzzleAllData.AddRange(e.InPacket.PuzzleData);
            if (e.InPacket.NextFragmentIndex != 0)
            {
                this.SendToken2(e.InPacket.NextImageToken, "", e.InPacket.NextFragmentIndex);
            }
            else
            {
                if (NeedVerifyCode != null)
                {
                    NeedVerifyCode(this.QQClient, e);
                }
            }
        }

        /// <summary>
        /// 密码正确
        /// </summary>
        public event EventHandler<QQEventArgs<_08LoginKeyPacket, _08LoginKeyReplyPacket>> PasswordChecked;
        internal void OnPasswordChecked(QQEventArgs<_08LoginKeyPacket, _08LoginKeyReplyPacket> e)
        {
            SendLogin();
            if (PasswordChecked != null)
            {
                PasswordChecked(this.QQClient, e);
            }
        }

        /// <summary>
        /// 密码错误
        /// </summary>
        public event EventHandler<QQEventArgs<_08LoginKeyPacket, _08LoginKeyReplyPacket>> PasswordError;
        internal void OnPasswordError(QQEventArgs<_08LoginKeyPacket, _08LoginKeyReplyPacket> e)
        {
            if (PasswordError != null)
            {
                PasswordError(this.QQClient, e);
            }
        }

        /// <summary>
        /// 登录失败，未知原因
        /// </summary>
        public event EventHandler<QQEventArgs<_08LoginKeyPacket, _08LoginKeyReplyPacket>> CheckPasswordFailed;
        internal void OnCheckPasswordFailed(QQEventArgs<_08LoginKeyPacket, _08LoginKeyReplyPacket> e)
        {
            if (CheckPasswordFailed != null)
            {
                CheckPasswordFailed(this.QQClient, e);
            }
        }

        /// <summary>
        /// 登录成功
        /// </summary>
        public event EventHandler<QQEventArgs<_08LoginPacket, _08LoginReplyPacket>> LoginSuccessfully;
        internal void OnLoginSuccessfully(QQEventArgs<_08LoginPacket, _08LoginReplyPacket> e)
        {
            ProcessLoginSuccess();
            if (LoginSuccessfully != null)
            {
                LoginSuccessfully(this.QQClient, e);
            }
        }

        /// <summary>
        /// 登录失败
        /// </summary>
        public event EventHandler<QQEventArgs<_08LoginPacket, _08LoginReplyPacket>> LoginFailed;
        internal void OnLoginFailed(QQEventArgs<_08LoginPacket, _08LoginReplyPacket> e)
        {
            if (LoginFailed != null)
            {
                LoginFailed(this.QQClient, e);
            }
        }

        /// <summary>
        /// 需要重新手工选择一台服务器登录
        /// </summary>
        public event EventHandler<QQEventArgs<_08LoginPacket, _08LoginReplyPacket>> LoginRedirect;
        internal void OnLoginRedirect(QQEventArgs<_08LoginPacket, _08LoginReplyPacket> e)
        {
            if (LoginRedirect != null)
            {
                LoginRedirect(this.QQClient, e);
            }
        }

        /// <summary>
        /// 未知登录错误
        /// </summary>
        public event EventHandler<QQEventArgs<_08LoginPacket, _08LoginReplyPacket>> LoginUnknowError;
        internal void OnLoginUnknowError(QQEventArgs<_08LoginPacket, _08LoginReplyPacket> e)
        {
            if (LoginUnknowError != null)
            {
                LoginUnknowError(this.QQClient, e);
            }
        }

        /// <summary>
        /// Occurs when [request key successfully].
        /// </summary>
        public event EventHandler<QQEventArgs<GetKeyPacket, GetKeyReplyPacket>> RequestKeySuccessfully;
        internal void OnRequestKeySuccessfully(QQEventArgs<GetKeyPacket, GetKeyReplyPacket> e)
        {
            if (RequestKeySuccessfully != null)
            {
                RequestKeySuccessfully(this.QQClient, e);
            }
        }

        public event EventHandler<QQEventArgs<GetKeyPacket, GetKeyReplyPacket>> RequestKeyFailed;
        internal void OnRequestKeyFailed(QQEventArgs<GetKeyPacket, GetKeyReplyPacket> e)
        {
            if (RequestKeyFailed != null)
            {
                RequestKeyFailed(this.QQClient, e);
            }
        }


        /// <summary>接收到保持连接回复包
        /// 	<remark>abu 2008-03-10 </remark>
        /// </summary>
        public event EventHandler<QQEventArgs<_08KeepAlivePacket, _08KeepAliveReplyPacket>> ReceivedKeepAlive;
        internal void OnReceivedKeepAlive(QQEventArgs<_08KeepAlivePacket, _08KeepAliveReplyPacket> e)
        {
            if (ReceivedKeepAlive != null)
            {
                ReceivedKeepAlive(this, e);
            }
        }


        public event EventHandler<QQEventArgs<_08AuthInfoOpPacket, _08AuthInfoOpReplyPacket>> ReceivedAuthInfo;
        internal void OnReceivedAuthInfo(QQEventArgs<_08AuthInfoOpPacket, _08AuthInfoOpReplyPacket> e)
        {
            if (ReceivedAuthInfo != null)
            {
                ReceivedAuthInfo(this, e);
            }
        }


        #endregion
    }
}
